package com.yanxu.design01_singleton.lazy;

/**
 * @author 折戟沉沙铁未销
 * @version V1.0
 * @date 2025/4/9-2025
 * @Description: 懒汉式-单例
 */
public class Lazy01_Singleton {
    //定义
    private static Lazy01_Singleton lazySingleton = null;

    //构造方法私有化
    private Lazy01_Singleton() {
    }

    /**
     * 版本1：
     *  获取 LazySingleton 实例对象
     *  这种写法在多线程情况下，并不能保证 LazySingleton 只创建1次。
     */
    public static Lazy01_Singleton getInstance1() {
        if (lazySingleton == null){
            lazySingleton=new Lazy01_Singleton();
        }
        return lazySingleton;
    }

    /**
     * 版本2：
     *  通过在方法上 加锁 的形式，保证单例
     *  但是这种情况是有性能损耗的。
     *  第一次创建对象加锁没有问题，但是单例对象已经存在了，后面每次获取也都需要先获取锁，这就拉低了性能了。
     */
    public synchronized static Lazy01_Singleton getInstance2() {
        if (lazySingleton == null) {
            lazySingleton = new Lazy01_Singleton();
        }
        return lazySingleton;
    }

    /**
     * 版本3：
     *  通过 synchronized锁 代码块的形式，保证保证单例
     *  这种写法，本质和 版本2 的写法没有任何区别。
     *  也是带来了性能的损耗，因为即使单例对象已经存在了，后面仅仅是获取单例对象，也需要先获取锁。拉低了性能。
     *
     */
    public static Lazy01_Singleton getInstance3() {
        synchronized (Lazy01_Singleton.class){
            if (lazySingleton == null){
                lazySingleton = new Lazy01_Singleton();
            }
        }
        return lazySingleton;
    }

    /*
    * getInstance2()、getInstance3() 都已经保证了单例
    * 但是，这两种方法因为加锁，每一个线程获取单例，必须先得获取锁。这样的性能是比较低的。
    * 所以，我们是不是可以将锁的粒度，范围变小，只有 instance是 null,需要创建的时候再加锁。如果 instance 已经存在了，就直接返回呢？
    * 即：将锁的粒度尽量变小。
    * 在这样的思想下，我们又衍生出了 【双重检查】 机制。
    * */
}